/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <flgrCoreData.h>
#include <flgrCoreVector.h>
#include <flgrCoreArithVector.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreDataIO.h>
#include "flgrCoreTranspose.h"
#include "flgrCoreTransposeFast.h"


////////////////////////////////////////////////////////////////////////////
// Macro for different type of transposeData2D
//////////////////////////////////////////////////////////////////
#define FLGR_MACRO_TRANSPOSE(dtype)					\
  FLGR_Vector *vec = flgr_vector_create(datsrc->spp,datsrc->type);	\
  int size_y, size_x;							\
  int i,j;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  size_y=datsrc->size_y;						\
  size_x=datsrc->size_x;						\
									\
  for(i=0;i<size_y;i++) {						\
    for(j=0;j<size_x;j++) {						\
      flgr2d_get_data_vector_##dtype(datsrc,i,j,vec);			\
      flgr2d_set_data_vector_##dtype(datdest,j,i,vec);			\
    }									\
  }									\
									\
  flgr_vector_destroy(vec);						\
  return


void flgr2d_transpose_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_TRANSPOSE(fgBIT);
}

void flgr2d_transpose_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT8(datdest,datsrc);

  }else if(datdest->spp==2) {
    flgr2d_transpose_fast_fgUINT16(datdest,datsrc);

  }else if(datdest->spp==4) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);

  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT8);
  }
#else
#ifdef __MMX__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT8(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT8);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgUINT8);
#endif
#endif
}

void flgr2d_transpose_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT16(datdest,datsrc);
  }else if(datdest->spp==2) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT16);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgUINT16);
#endif
}

void flgr2d_transpose_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT32);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgUINT32);
#endif
}

void flgr2d_transpose_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT8(datdest,datsrc);
  }else if(datdest->spp==2) {
    flgr2d_transpose_fast_fgUINT16(datdest,datsrc);
  }else if(datdest->spp==4) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT8);
  }
#else
#ifdef __MMX__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT8(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgUINT8);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgUINT8);
#endif
#endif
}

void flgr2d_transpose_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT16(datdest,datsrc);
  }else if(datdest->spp==2) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgINT16);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgINT16);
#endif
}

void flgr2d_transpose_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgINT32);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgINT32);
#endif
}

void flgr2d_transpose_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
#ifdef __SSE2__
  if(datdest->spp==1) {
    flgr2d_transpose_fast_fgUINT32(datdest,datsrc);
  }else {
    FLGR_MACRO_TRANSPOSE(fgFLOAT32);
  }
#else
  FLGR_MACRO_TRANSPOSE(fgFLOAT32);
#endif
}

void flgr2d_transpose_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {
  FLGR_MACRO_TRANSPOSE(fgFLOAT64);
}

FLGR_Ret flgr2d_transpose(FLGR_Data2D *datdest, FLGR_Data2D *datsrc) {

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if(flgr2d_is_data_same_type(datdest, datsrc)!=0) {
    POST_ERROR("src type and dest type different!\n");
    return FLGR_RET_TYPE_DIFFERENT;
  }

  if(flgr2d_is_data_same_spp(datdest, datsrc)!=0) {
    POST_ERROR("src SPP and dest SPP different!\n");
    return FLGR_RET_UNDEFINED_ERROR;
  }

  if((datdest->size_x!=datsrc->size_y)||(datdest->size_y!=datsrc->size_x)) {
    POST_ERROR("src size and dest size incompatible!\n");
    return FLGR_RET_SIZE_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr2d_transpose,datdest, datsrc);

}

